﻿#include "GxImageGadgetPrivate.h"
#include "GxImageGadget.h"
#include <QEvent>
#include <QPainter>
#include <QDebug>
#include <QThread>
#include <QGuiApplication>
#include <QApplication>
#include <QSettings>
#include <QLinearGradient>
#include <QTimer>
#include <QSystemTrayIcon>
#include <QMenu>
#include <QIcon>
#include <QTimeLine>
#include <QSlider>
#include <QWidgetAction>
#include <QLabel>
#include <QBoxLayout>

#include "GxImageOperator.h"
#include "GxImageSetting.h"
#include "GxResizeProc.h"
#include "util.h"

#define     switchOnIcon            QIcon(":/resource/toggle2-on")
#define     switchOffIcon           QIcon(":/resource/toggle2-off")
#define     lockIcon                QIcon(":/resource/lock")
#define     unlockIcon              QIcon(":/resource/unlock")

GxImageGadgetPrivate::GxImageGadgetPrivate(GxImageGadget *obj)
    : QObject()
    , q_ptr(obj)
    , m_pCurrentImage(new QPixmap(QSize(0,0)))
    , m_ratioRule(RR_KeepRatio)
    , m_sizeRule(SR_KeepSizePossible)
    , m_slideMode(SM_InTurn)
    , m_interval(util::getSettingInterval())
    , m_pTimer(new QTimeLine(m_interval*1000, this))
    , m_pSetting(nullptr)
    , m_bInMaintance(false)
    , m_pTray(nullptr)
    , m_pActionPlay(nullptr)
    , m_pActionLock(nullptr)
    , m_pActionUnlock(nullptr)
    , m_pActionPanelOn(nullptr)
    , m_pActionPanelOff(nullptr)
    , m_pActionSetting(nullptr)
    , m_pActionExit(nullptr)
    , m_pResizeProc(new GxResizeProc(q_ptr))
{
    Q_Q(GxImageGadget);
    QRect rect = util::getSettingGeometry();
    if (rect.x() >= 0 && rect.y() >= 0)
    {
        q->setGeometry(rect);
        resetMaintainByMoving(10);
    }
    q->installEventFilter(this);
    this->installEventFilter(this);

    m_pTimer->setLoopCount(1);
    connect(m_pTimer, &QTimeLine::finished, this, &GxImageGadgetPrivate::goNext);
    connect(m_pTimer, &QTimeLine::finished, m_pTimer, &QTimeLine::start);
    connect(m_pTimer, &QTimeLine::valueChanged, [&](qreal value)
            { 
                //qDebug() << "timer value" << value; 
            });
#if SHOW_PROGRESS_BAR
    this->startTimer(20);
#endif
    //托盘区
    initTray();

    //数据库
    initDB();

    genMaintancePixmap();

    m_pResizeProc->setResizable(false);

    //默认显示中文
    util::setLanguage("Chinese");
}

GxImageGadgetPrivate::~GxImageGadgetPrivate()
{
    if (m_pWorker)
    {
        qDebug() << "to delete worker";
        m_pWorker->deleteLater();
        m_pWorker = nullptr;
    }
}

void GxImageGadgetPrivate::setSlideShowInterval(int interval)
{
    if(interval <= 0 || interval == m_interval)
        return;
    m_interval = interval;
    qDebug() << "set interval to " << m_interval << (m_interval==1 ? "second" : "seconds");
    //保存
    util::saveSettingInterval(m_interval);
    
    //设置间隔
    if(m_pTimer)
    {
        m_pTimer->setDuration(m_interval * 1000);
    }
}

void GxImageGadgetPrivate::addDir(const QString& dir)
{
    //递归字段暂时无效，不递归
    DBOperationInfo node;
    node.type = OT_ADDDIR;
    node.strDir = dir;
    //node.bRecursive = recursive;
    emit signalSendContent(node);
}

void GxImageGadgetPrivate::removeDir(const QString& dir)
{
    DBOperationInfo node;
    node.type = OT_REMOVEDIR;
    node.strDir = dir;
    emit signalSendContent(node);
}

void GxImageGadgetPrivate::goNext()
{
    DBOperationInfo node;
    node.type = OT_NEXT;
    emit signalSendContent(node);
}

void GxImageGadgetPrivate::goPrevious()
{
    DBOperationInfo node;
    node.type = OT_PREVIOUS;
    emit signalSendContent(node);
}

void GxImageGadgetPrivate::stop(bool resetimage/*=false*/)
{
    Q_Q(GxImageGadget);

    //定时器已经在运行，则不需要处理
    if(m_pTimer->state() == QTimeLine::Running)
    {
        m_pTimer->setPaused(true);
    }

    if(resetimage)
    {
        delete m_pCurrentImage;
        m_pCurrentImage = new QPixmap(QSize(0, 0));
        q->update();
    }

    //处理播放按钮的状态
    //slotPlayAction(true);
    if(m_pActionPlay && m_pActionPlay->isChecked()!=true)
    {
        m_pActionPlay->setChecked(true);
    }
}

void GxImageGadgetPrivate::start()
{
    //启动定时器
    switch (m_pTimer->state())
    {
        case QTimeLine::NotRunning:
        {
            //第一次，才刚刚初始化，则获取第一张照片
            goNext();
            m_pTimer->start();
        }
        break;

        case QTimeLine::Paused:
        {
            m_pTimer->setPaused(false);
        }
        break;

        case QTimeLine::Running:
        {
            //已经在运行，什么都不用做，跳出去，设置菜单状态
        } 
        break;

        default:
            break;
    }

    //处理播放菜单的状态
    if(m_pActionPlay && m_pActionPlay->isChecked()!=false)
    {
        m_pActionPlay->setChecked(false);
    }
}

bool GxImageGadgetPrivate::eventFilter(QObject *watched, QEvent *event)
{
    Q_Q(GxImageGadget);
    if (watched == q)
    {
        switch (event->type())
        {
            //绘制事件
            case QEvent::Paint:
            {
                draw();
            }
            break;

            //双击事件
            // case QEvent::MouseButtonDblClick:
            // {
            //     //且按住Ctrl,表示打开配置对话框
            //     Qt::KeyboardModifiers mods = QGuiApplication::keyboardModifiers();
            //     if(mods == Qt::ControlModifier)
            //     {
            //         openSetting();
            //     }
            // }
            // break;

            //移动缩放事件
            case QEvent::Resize:
            case QEvent::Move:
            {
                util::saveSettingGeometry(q->geometry());
//                 if(m_bInMaintance)
//                 {
// #if SHOW_PROGRESS_BAR
//                     m_rectProgress = q->rect();
//                     m_rectProgress.setHeight(5);
//                     m_rectProgress.moveBottom(q->rect().bottom());
// #endif
//                     q->update();
//                 }
            }
            break;

            case QEvent::Close:
            {
                qDebug() << "close prevent";
                event->ignore();
                return true;
            }

            case QEvent::LanguageChange:
            {
                //翻译
                reTranslate();
            }
            break;

            default:
			{
				qDebug() << event->type();
			}
            break;
        }

    }
#if SHOW_PROGRESS_BAR
    else if(watched == this)
    {
        switch (event->type())
        {
            //绘制事件
            case QEvent::Timer:
            {
                //更新
                q->update(m_rectProgress);
            }
            break;


            default:
                break;
        }
    }
#endif

    return QObject::eventFilter(watched, event);
}

void GxImageGadgetPrivate::initTray()
{
    Q_Q(GxImageGadget);
    bool bSupportTray = QSystemTrayIcon::isSystemTrayAvailable();
    qDebug() << "suport tray " << bSupportTray;
    if(!bSupportTray)
        return;

    if(!m_pTray)
    {
        m_pTray = new QSystemTrayIcon(q);
        //设置图标
        m_pTray->setIcon(QIcon(":/resource/tray"));

        QMenu *pMenu = new QMenu(q);

        //checked表示暂停状态
        //uncheck表示播放状态
        m_pActionPlay = pMenu->addAction(switchOffIcon, tr("Pause"), this, SLOT(slotPlayActionTrigerred(bool)));
        m_pActionPlay->setCheckable(true);

        pMenu->addSeparator();
        m_pActionLock = pMenu->addAction(lockIcon, tr("Lock"), this, SLOT(slotLockActionTriggered()));
        m_pActionUnlock = pMenu->addAction(unlockIcon, tr("Unlock"), this, SLOT(slotLockActionTriggered()));
        m_pActionLock->setData("Lock");
        m_pActionUnlock->setData("Unlock");
        //组
        QActionGroup* pLockGroup = new QActionGroup(this);
        pLockGroup->addAction(m_pActionLock);
        pLockGroup->addAction(m_pActionUnlock);
        m_pActionLock->setCheckable(true);
        m_pActionLock->setChecked(true);
        m_pActionUnlock->setCheckable(true);

        pMenu->addSeparator();

        m_pActionPanelOn = pMenu->addAction(QIcon(":/resource/panel-on"), tr("Show Panel"), q, SLOT(show()));
        m_pActionPanelOff = pMenu->addAction(QIcon(":/resource/panel-off"), tr("Hide Panel"), q, SLOT(hide()));
        //组
        QActionGroup* pPanelGroup = new QActionGroup(this);
        pPanelGroup->addAction(m_pActionPanelOn);
        pPanelGroup->addAction(m_pActionPanelOff);
        m_pActionPanelOn->setCheckable(true);
        m_pActionPanelOn->setChecked(true);
        m_pActionPanelOff->setCheckable(true);

        pMenu->addSeparator();

#if		0
        //滑条
        QSlider *pSlider = new QSlider(Qt::Horizontal, q);
        pSlider->setRange(1, 120);
        pSlider->setValue(5);
        pSlider->setFixedHeight(20);
        pSlider->setMinimumWidth(100);

        QLabel *pLabel = new QLabel(q);
        pLabel->setFixedSize(50, 20);

		QWidget* pWidget = new QWidget(q);
		QVBoxLayout* pSliderLayout = new QVBoxLayout(pWidget);
		pSliderLayout->setContentsMargins(0, 0, 0, 0);
		pSliderLayout->setSpacing(0);
		pSliderLayout->addWidget(pLabel);
		pSliderLayout->addWidget(pSlider);
		connect(pSlider, &QSlider::valueChanged, [=](int value) {
			pLabel->setNum(value);
		});
		

        QWidgetAction *pActionSlider = new QWidgetAction(pMenu);
        pActionSlider->setDefaultWidget(pWidget);
        pMenu->addAction(pActionSlider);

        pMenu->addSeparator();
#endif

        m_pActionSetting = pMenu->addAction(QIcon(":/resource/setting"), tr("Setting"), this, &GxImageGadgetPrivate::openSetting);

        pMenu->addSeparator();

        m_pActionExit = pMenu->addAction(QIcon(":/resource/exit"), tr("Quit"), qApp, &QApplication::quit);

        m_pTray->setContextMenu(pMenu);

        m_pTray->show();
    }
}

void GxImageGadgetPrivate::initDB()
{
    qRegisterMetaType<DBOperationInfo>("DBOperationInfo");

    int index = util::getSettingIndex();
    m_pWorker = new GxImageOperator(this, index);
    //线程
    m_pThread = new QThread();
    m_pWorker->moveToThread(m_pThread);
    //开始线程
    connect(m_pThread, SIGNAL(started()), m_pWorker, SLOT(work()));
    //数据
    //connect(m_pWorker, SIGNAL(signalCheckInfo(bool,const QString&)), this, SLOT(slotUserLoginResult(bool,const QString&)));  //跨线程，队列连接
    //跨线程，队列连接
    connect(this, SIGNAL(signalSendContent(DBOperationInfo)), m_pWorker, SLOT(push(DBOperationInfo)));    

    //connect(m_pWorker, SIGNAL(done()), m_pWorker, SLOT(deleteLater()));
    //这里一定要用同步的方式来连接，否则线程退不出来QThread: Destroyed while thread is still running
    connect(m_pWorker, SIGNAL(destroyed()), m_pThread, SLOT(quit()), Qt::DirectConnection);
    connect(m_pThread, SIGNAL(finished()), m_pThread, SLOT(deleteLater()));
    //监视打印
    connect(m_pWorker, &QObject::destroyed, [&]()
            {
                qDebug() << "worker destroyed";
            });
    connect(m_pThread, &QObject::destroyed, [&]()
            {
                qDebug() << "thread destroyed";
            });

    //启动线程
    m_pThread->start();
    //m_pWorker->push(DBOperationInfo(OT_NEXT));
}

void GxImageGadgetPrivate::draw()
{
    Q_Q(GxImageGadget);
    QPainter painter;
    
    //开启画布绘制
    painter.begin(q);
    painter.setRenderHint(QPainter::Antialiasing, true);
    //painter.setRenderHint(QPainter::SmoothPixmapTransform, true);

#if 0
    //绘制背景平铺格
    if(m_bInMaintance && !m_pixmapForMaintanceBg.isNull())
    {
        QRect targetRect = q->rect();
        painter.drawTiledPixmap(targetRect, m_pixmapForMaintanceBg);
    }
#endif

    if(!m_pCurrentImage->isNull())
    {
        //缩放并绘制图片
        QRect sourceRect = m_pCurrentImage->rect();
#if 0
        QRect targetRect = calcTargetRect(sourceRect);
        if (!targetRect.isNull())
        {
            painter.drawPixmap(targetRect, *m_pCurrentImage, m_pCurrentImage->rect());
        }
#else
        QRect targetRect = q->rect();
        QPixmap image = m_pCurrentImage->scaled(targetRect.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
        sourceRect = image.rect();
        targetRect = calcTargetRect(sourceRect);
        if (!targetRect.isNull())
        {
            painter.drawPixmap(targetRect, image, image.rect());
        }
#endif        
    }
    else
    {
        //绘制一个默认图片，如logo
        //TODO
        painter.fillRect(q->rect(), Qt::red);
    }

    //维护状态下的绘制
    if (m_bInMaintance && !m_pixmapForMaintanceCorner.isNull())
    {
        QRect targetRect = q->rect();
        painter.save();
        //左上角
        painter.drawPixmap(0, 0, m_pixmapForMaintanceCorner);
        //右上角
        painter.translate(targetRect.width(), 0);
        painter.rotate(90);
        painter.drawPixmap(0, 0, m_pixmapForMaintanceCorner);
        //右下角
        painter.translate(targetRect.height(), 0);
        painter.rotate(90);
        painter.drawPixmap(0, 0, m_pixmapForMaintanceCorner);
        //左下角
        painter.translate(targetRect.width(), 0);
        painter.rotate(90);
        painter.drawPixmap(0, 0, m_pixmapForMaintanceCorner);

        painter.resetTransform();
        painter.restore();
    }

#if SHOW_PROGRESS_BAR
    //绘制一个进度条
    qreal rValue = m_pTimer->currentValue();
    QRect progress = m_rectProgress;
    progress.setWidth(progress.width() * rValue);
    painter.save();
    painter.fillRect(progress, Qt::red);
    painter.restore();
#endif

    //结束画布绘制
    painter.end();
}

QRect GxImageGadgetPrivate::calcTargetRect(const QRect &rect) const
{
    Q_Q(const GxImageGadget);
    QRect target = q->rect();
    if(target.isNull() || rect.isNull())
        return QRect();


    //图片长宽都不大于画布
    if(rect.width() <= target.width() && rect.height() <= target.height())
    {
        //当需要保持图片大小
        if(m_sizeRule == SR_KeepSizePossible)
        {
            //直接返回图片大小
            return rect;
        }
    }

    //使rect适配target大小
    switch (m_ratioRule)
    {
        //保持比例
        case RR_KeepRatio:
        {
            //图片宽度和画布宽度的比例
            qreal rWidthRatio = rect.width() * 1.0 / target.width();
            //图片高度和画布高度的比例
            qreal rHeightRatio = rect.height() * 1.0 / target.height();
            //最终比例，取较大值
            qreal rScaleRatio = qMax(rWidthRatio, rHeightRatio);

            // qDebug() << "target" << target << "source " << rect;
            // qDebug() << "wr" << rWidthRatio << "hr" << rHeightRatio << "fr" << rScaleRatio;

            if(qFuzzyIsNull(rScaleRatio))
                return QRect();

            int iWidth = rect.width() / rScaleRatio;
            int iHeight = rect.height() / rScaleRatio;
            QRect rectShouldBe(0, 0, iWidth, iHeight);
            rectShouldBe.moveCenter(target.center());
            return rectShouldBe;
        }
        break;

        //填满画布
        case RR_IgnoreRatio:
        {
            return target;
        }

        default:
            break;
    }

    return QRect();
}

void GxImageGadgetPrivate::setCurrentImage(const QString& strImage)
{
    Q_Q(GxImageGadget);
    //qDebug() << __FUNCTION__ << strImage;
    QFileInfo fileinfo(strImage);
    if(!fileinfo.isFile())
    {
        return;
    }
    //加载图片
    m_pCurrentImage->load(strImage);
    q->update();

    util::saveSettingIndex(m_pWorker->index()-1);
}

void GxImageGadgetPrivate::genMaintancePixmap()
{
    static QColor color = Qt::white;
    static int iColorWidth = 5;
    static int iWdith = 50;

    QRegion r1(QRect(0, 0, iWdith, iColorWidth));
    QRegion r2(QRect(0, iColorWidth, iColorWidth, iWdith));
    QRegion r3 = r1.united(r2);

    m_pixmapForMaintanceCorner = QPixmap(iWdith, iWdith);
    m_pixmapForMaintanceCorner.fill(Qt::transparent);

    QPainter painter;
    painter.begin(&m_pixmapForMaintanceCorner);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setClipRegion(r3);
    QLinearGradient linearGrad(QPointF(0, 0), QPointF(40, 40));
    linearGrad.setColorAt(0, Qt::white);
    linearGrad.setColorAt(1, Qt::blue);
    painter.setBrush(linearGrad);
    painter.drawRect(0, 0, iWdith, iWdith);
    painter.end();

    //背景
    static QRect rectBg = QRect(0,0,40,40);
    m_pixmapForMaintanceBg = QPixmap(64, 64);
    m_pixmapForMaintanceBg.fill(Qt::white);
    painter.begin(&m_pixmapForMaintanceBg);
    QColor colorBg(Qt::black);
    color.setAlpha(120);
    painter.fillRect(0, 0, 32, 32, colorBg);
    painter.fillRect(32, 32, 32, 32, colorBg);
    painter.end();
}

void GxImageGadgetPrivate::resetMaintainByMoving(int deltamsecs)
{
    if (deltamsecs < 0)
        return;
 
    static QTimer timer;
    //FIX:必须单发，否则会不停的重置
    timer.setSingleShot(true);
    connect(&timer, &QTimer::timeout, this, &GxImageGadgetPrivate::setMaintainToFalse, Qt::UniqueConnection);
    timer.start(deltamsecs);
}

void GxImageGadgetPrivate::reTranslate()
{
    Q_Q(GxImageGadget);
    //标题
    q->setWindowTitle(tr("Image Gadget"));
    //播放暂停菜单项
    m_pActionPlay->setText(m_pActionPlay->isChecked() ? tr("Start") : tr("Pause"));
    m_pActionLock->setText(tr("Lock"));
    m_pActionUnlock->setText(tr("Unlock"));
    m_pActionPanelOn->setText(tr("Show Panel"));
    m_pActionPanelOff->setText(tr("Hide Panel"));
    m_pActionSetting->setText(tr("Setting"));
    m_pActionExit->setText(tr("Quit"));


}

void GxImageGadgetPrivate::setMaintainToFalse()
{
    Q_Q(GxImageGadget);
    m_bInMaintance = (m_pSetting && m_pSetting->isVisible());
    q->update();
}

void GxImageGadgetPrivate::openSetting()
{
    Q_Q(GxImageGadget);
    if (!m_pSetting)
    {
        m_pSetting = new GxImageSetting(q);
        connect(m_pSetting, &GxImageSetting::signalToAddDir, this, &GxImageGadgetPrivate::addDir);
        connect(m_pSetting, &GxImageSetting::signalToRemoveDir, this, &GxImageGadgetPrivate::removeDir);
        connect(m_pSetting, &GxImageSetting::signalIntervalChanged, this, &GxImageGadgetPrivate::setSlideShowInterval);
        connect(m_pSetting, &GxImageSetting::signalResetGeometry, this, &GxImageGadgetPrivate::slotResetGeometry);
        m_pSetting->setModel(m_pWorker->getModel());
    }
    m_bInMaintance = true;
    m_pResizeProc->setResizable(true);
    q->update();

    m_pSetting->show();

    m_bInMaintance = false;
    m_pResizeProc->setResizable(false);
    q->update();
}

//checked表示暂停状态
//uncheck表示播放状态
void GxImageGadgetPrivate::slotPlayActionTrigerred(bool bState)
{
    QAction *pAction = qobject_cast<QAction*>(sender());
    //qDebug() << pAction;
    if (pAction)
    {
        //来自菜单点击
        //checked表示暂停状态
        //uncheck表示播放状态
        pAction->setText(bState ? tr("Start") : tr("Pause"));
        pAction->setIcon(bState ? switchOffIcon : switchOnIcon);

        //控制播放暂停
        bState ? stop() : start();
    }
}

void GxImageGadgetPrivate::slotLockActionTriggered()
{
    Q_Q(GxImageGadget);
    QAction *pAction = qobject_cast<QAction *>(sender());
    if (!pAction)
    {
        return;
    }

    QString str = pAction->data().toString();
    if(str == "Lock")
    {
        m_bInMaintance = false;
        m_pResizeProc->setResizable(false);
    }
    else if(str == "Unlock")
    {
        m_bInMaintance = true;
        m_pResizeProc->setResizable(true);
    }
    q->update();
}

void GxImageGadgetPrivate::slotResetGeometry()
{
    Q_Q(GxImageGadget);
    q->setGeometry(0, 0, 700, 500);
}
